home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / lfsrebuild / checkdir.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-12  |  43.6 KB  |  1,623 lines

  1. /* 
  2.  * checkdir.c --
  3.  *
  4.  *    Routines to allow moving through a files block pointers.
  5.  *
  6.  * Copyright 1989 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/cmds/fscheck/RCS/checkdir.c,v 1.29 90/10/10 15:29:03 mendel Exp $ SPRITE (Berkeley)";
  18. #endif not lint
  19.  
  20. #include <option.h>
  21. #include "fscheck.h"
  22. #include <list.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <ctype.h>
  26.  
  27. static  int         lostFoundFileNum = -1;
  28. static    char        pathName[FS_MAX_PATH_NAME_LENGTH];
  29.  
  30. int foundError;
  31. int verbose = 1;
  32. int debug = 0;
  33. int tooBig = 0;
  34. static int        diskFd;
  35.  
  36. Fsdm_FileDescriptor    *rootFDPtr, *lostFoundFDPtr;
  37. List_Links    modListHdr;
  38.  
  39.  
  40. static int MakePtrAccessible _ARGS_((register DirIndexInfo *indexInfoPtr));
  41. static int GetFirstIndex _ARGS_((int blockNum, register DirIndexInfo *indexInfoPtr));
  42. static int GetNextIndex _ARGS_((register DirIndexInfo *indexInfoPtr));
  43. static void OpenDir _ARGS_((Fsdm_FileDescriptor *fdPtr, FdInfo *fdInfoPtr, DirIndexInfo *indexInfoPtr, Fslcl_DirEntry **dirEntryPtrPtr));
  44. static void NextDirEntry _ARGS_((DirIndexInfo *indexInfoPtr, Fslcl_DirEntry **dirEntryPtrPtr));
  45. static void CloseDir _ARGS_((DirIndexInfo *indexInfoPtr));
  46. static void CheckDir _ARGS_((int fdNum, Fsdm_FileDescriptor *fdPtr, FdInfo *fdInfoPtr, int parentFdNum, int lostDirNum, int *dirOKPtr));
  47. static ReturnStatus AddToDirectory _ARGS_(( int    dirNumber,
  48.     Fsdm_FileDescriptor *dirFDPtr, DirIndexInfo *dirIndexPtr, 
  49.     Fslcl_DirEntry    **dirEntryPtrPtr,  int    fileNumber,  char *fileName,
  50.     FdInfo    *fdInfoPtr));
  51. static void WriteModDescs _ARGS_((int diskId));
  52.  
  53. #define DIRFULL 2
  54.  
  55.  
  56. /*
  57.  *----------------------------------------------------------------------
  58.  *
  59.  * FetchFileDesc --
  60.  *
  61.  *    Return a file descriptor.
  62.  *
  63.  * Results:
  64.  *    1 if the file descriptor is successfully read or 0 if the descriptor 
  65.  *    was unreadable.
  66.  *
  67.  * Side effects:
  68.  *    A file descriptor may be allocated.
  69.  *
  70.  *----------------------------------------------------------------------
  71.  */
  72. int
  73. FetchFileDesc(fdNum, fdPtrPtr)
  74.     int            fdNum;        /* Number of descriptor to fetch. */
  75.     Fsdm_FileDescriptor    **fdPtrPtr;    /* Where to store ptr to descriptor. */
  76. {
  77.     int bufSize,  j;
  78.     LfsFileDescriptor    *descPtr, *newDescPtr;
  79.     char *descBuf;
  80.     LfsDescMapEntry *descMapPtr;
  81.     ModListElement    *modElemPtr;
  82.  
  83.     if ((fdNum < 0) || (fdNum >= superBlockPtr->descMap.maxDesc)) {
  84.     return 0;
  85.     }
  86.     if (descInfoArray[fdNum].flags & FD_UNREADABLE) {
  87.     return 0;
  88.     }
  89.     if (descInfoArray[fdNum].flags & ON_MOD_LIST) {
  90.     LIST_FORALL(modList, (List_Links *)modElemPtr) {
  91.         if (modElemPtr->fdNum == fdNum) {
  92.         *fdPtrPtr = modElemPtr->fdPtr;
  93.         return(1);
  94.         }
  95.     }
  96.     fprintf(stderr, "FetchFileDesc: FD not found in mod list.\n");
  97.     abort();
  98.     }
  99.     bufSize = superBlockPtr->fileLayout.descPerBlock * sizeof(*descPtr);
  100.  
  101.     descBuf = alloca(bufSize);
  102.  
  103.     descMapPtr = DescMapEntry(fdNum);
  104.     if (!(descMapPtr->flags & LFS_DESC_MAP_ALLOCED)) {
  105. #ifdef PATCHROOT
  106.     Alloc(newDescPtr,LfsFileDescriptor,1);
  107.     *fdPtrPtr = (&newDescPtr->common);
  108.     if (tooBig) {
  109.         return 0;
  110.     }
  111.     bzero((char *) newDescPtr, sizeof(LfsFileDescriptor));
  112.     newDescPtr->fileNumber = fdNum;
  113.     return 1;
  114. #else
  115.     return 0;
  116. #endif
  117.     }
  118.     if (DiskRead(diskFd, descMapPtr->blockAddress, bufSize, descBuf)
  119.             != bufSize) {
  120.     return 0;
  121.     }
  122.     descPtr = (LfsFileDescriptor *)descBuf;
  123.     for (j = 0; j < superBlockPtr->fileLayout.descPerBlock; j++) {
  124.     if (!(descPtr->common.flags & FSDM_FD_ALLOC)) {
  125.         break;
  126.     }
  127.     if (descPtr->fileNumber == fdNum) {
  128.         break;
  129.     }
  130.     descPtr++;
  131.     }
  132.     if ((j >= superBlockPtr->fileLayout.descPerBlock) ||
  133.     !(descPtr->common.flags & FSDM_FD_ALLOC) ||
  134.     (descPtr->fileNumber != fdNum)) {
  135.     return 0;
  136.     }
  137.     Alloc(newDescPtr,LfsFileDescriptor,1);
  138.     (*fdPtrPtr) = (&newDescPtr->common);
  139.     if (tooBig) {
  140.     return 0;
  141.     }
  142.     bcopy((Address)descPtr, (Address)newDescPtr,  
  143.       sizeof(LfsFileDescriptor));
  144.     return(1);
  145. }
  146.  
  147.  
  148. /*
  149.  *----------------------------------------------------------------------
  150.  *
  151.  * StoreFileDesc --
  152.  *
  153.  *    Store a file descriptor on disk.
  154.  *
  155.  * Results:
  156.  *    None.
  157.  *
  158.  * Side effects:
  159.  *    An FdCheckInfo struct is allocated.
  160.  *
  161.  *----------------------------------------------------------------------
  162.  */
  163. void
  164. StoreFileDesc(fdNum, fdPtr)
  165.     int            fdNum;
  166.     Fsdm_FileDescriptor    *fdPtr;
  167. {
  168.     ModListElement    *modElemPtr;
  169.     if (descInfoArray[fdNum].flags & FD_MODIFIED) {
  170.     if (descInfoArray[fdNum].flags & ON_MOD_LIST) {
  171.         LIST_FORALL(modList, (List_Links *)modElemPtr) {
  172.         if (modElemPtr->fdNum == fdNum) {
  173.             /*
  174.              * The old fd may be in use on another list so we can't
  175.              * free it, but it may become unreferenced. 
  176.              */
  177.             modElemPtr->fdPtr = fdPtr;
  178.             return;
  179.         }
  180.         }
  181.         fprintf(stderr, "StoreFileDesc: FD not found in list.\n");
  182.         abort();
  183.     } else {
  184.         ModListElement    *modElemPtr;
  185.  
  186.         Alloc(modElemPtr,ModListElement,1);
  187.         if (tooBig) {
  188.         return;
  189.         }
  190.         descInfoArray[fdNum].flags |= ON_MOD_LIST;
  191.         modElemPtr->fdNum = fdNum;
  192.         modElemPtr->fdPtr = fdPtr;
  193.         List_Insert((List_Links *)modElemPtr, LIST_ATREAR(modList));
  194.     }
  195.     }
  196. }
  197.  
  198. /*
  199.  *----------------------------------------------------------------------
  200.  *
  201.  * MakePtrAccessible --
  202.  *
  203.  *    Make the pointer to the directory entry accessible.
  204.  *
  205.  * Results:
  206.  *    None.
  207.  *
  208.  * Side effects:
  209.  *    *indexInfoPtr modified.
  210.  *
  211.  *----------------------------------------------------------------------
  212.  */
  213. static int
  214. MakePtrAccessible(indexInfoPtr)
  215.     register    DirIndexInfo *indexInfoPtr;
  216. {
  217.     register int         *blockAddrPtr;
  218.     register Fsdm_FileDescriptor    *fdPtr;
  219.  
  220.     fdPtr = indexInfoPtr->fdPtr;
  221.  
  222.     blockAddrPtr = &indexInfoPtr->blockAddr;
  223.  
  224.     if (indexInfoPtr->indexType == INDIRECT) {
  225.     *blockAddrPtr = fdPtr->indirect[0];
  226.     } else {
  227.     *blockAddrPtr = fdPtr->indirect[1];
  228.     }
  229.  
  230.     /*
  231.      * Read first level block in.
  232.      */
  233.     if (indexInfoPtr->firstBlockNil) {
  234.     if (*blockAddrPtr == FSDM_NIL_INDEX) {
  235.         return(1);
  236.     }
  237.     if (DiskRead(diskFd,
  238.               *blockAddrPtr, FS_BLOCK_SIZE,
  239.               indexInfoPtr->firstBlock) != FS_BLOCK_SIZE) {
  240.         fprintf(stderr,"MakePtrAccessible: Read (1) failed block %d\n",
  241.                *blockAddrPtr);
  242.         return(0);
  243.     }
  244.     indexInfoPtr->firstBlockNil = 0;
  245.     }
  246.  
  247.     *blockAddrPtr = *(int *) (indexInfoPtr->firstBlock +
  248.                   sizeof(int) * indexInfoPtr->firstIndex);
  249.     if (indexInfoPtr->indexType == INDIRECT) {
  250.     return(1);
  251.     }
  252.  
  253.     /*
  254.      * Read second level block in.
  255.      */
  256.     if (*blockAddrPtr != FSDM_NIL_INDEX) {
  257.     if (DiskRead(diskFd, 
  258.               *blockAddrPtr, FS_BLOCK_SIZE,
  259.               indexInfoPtr->secondBlock) != FS_BLOCK_SIZE) {
  260.         fprintf(stderr,"MakePtrAccessible: Read (2) failed block %d\n",
  261.                *blockAddrPtr);
  262.         return(0);
  263.     }
  264.     indexInfoPtr->secondBlockNil = 0;
  265.     *blockAddrPtr = *(int *) (indexInfoPtr->secondBlock +
  266.                   sizeof(int) * indexInfoPtr->secondIndex);
  267.     }
  268.     return(1);
  269. }
  270.  
  271.  
  272. /*
  273.  *----------------------------------------------------------------------
  274.  *
  275.  * GetFirstIndex --
  276.  *
  277.  *    Initialize the index structure.  This will set up the index info
  278.  *    structure so that it contains a pointer to the desired block pointer.
  279.  *
  280.  * Results:
  281.  *    1 if could set up the index, 0 if could not.
  282.  *
  283.  * Side effects:
  284.  *    The index structure is initialized.
  285.  *
  286.  *----------------------------------------------------------------------
  287.  */
  288. static int
  289. GetFirstIndex(blockNum, indexInfoPtr)
  290.     int                  blockNum;      /* Where to start indexing. */
  291.     register DirIndexInfo     *indexInfoPtr; /* Index structure to initialize.*/
  292. {
  293.     int            indirectBlock;
  294.     Fsdm_FileDescriptor    *fdPtr;
  295.  
  296.     indexInfoPtr->firstBlockNil = 1;
  297.     indexInfoPtr->secondBlockNil = 1;
  298.     indexInfoPtr->blockNum = blockNum;
  299.     indexInfoPtr->dirDirty = 0;
  300.  
  301.     fdPtr = indexInfoPtr->fdPtr;
  302.  
  303.     if (blockNum < FSDM_NUM_DIRECT_BLOCKS) {
  304.     /*
  305.      * This is a direct block.
  306.      */
  307.     indexInfoPtr->indexType = DIRECT;
  308.     indexInfoPtr->firstIndex = blockNum;
  309.     indexInfoPtr->blockAddr = fdPtr->direct[blockNum];
  310.     return(1);
  311.     }
  312.  
  313.     /*
  314.      * Is an indirect block.
  315.      */
  316.     blockNum -= FSDM_NUM_DIRECT_BLOCKS;
  317.     indirectBlock = blockNum / FSDM_INDICES_PER_BLOCK;
  318.     if (indirectBlock == 0) {
  319.     /*
  320.      * This is a singly indirect block.
  321.      */
  322.     indexInfoPtr->indexType = INDIRECT;
  323.     indexInfoPtr->firstIndex = blockNum;
  324.     } else {
  325.     /*
  326.      * This a doubly indirect block.
  327.      */
  328.     indexInfoPtr->indexType = DBL_INDIRECT;
  329.     indexInfoPtr->firstIndex = indirectBlock - 1;
  330.     indexInfoPtr->secondIndex = blockNum -
  331.                     indirectBlock * FSDM_INDICES_PER_BLOCK;
  332.     }
  333.  
  334.     /*
  335.      * Finish off by making the block pointer accessible.  This may include
  336.      * reading indirect blocks into the cache.
  337.      */
  338.     return(MakePtrAccessible(indexInfoPtr));
  339. }
  340.  
  341.  
  342. /*
  343.  *----------------------------------------------------------------------
  344.  *
  345.  * GetNextIndex --
  346.  *
  347.  *    Put the correct pointers in the index structure to access the
  348.  *    block after the current block.
  349.  *
  350.  * Results:
  351.  *    None.
  352.  *
  353.  * Side effects:
  354.  *    The allocation structure is modified.
  355.  *
  356.  *----------------------------------------------------------------------
  357.  */
  358. static int
  359. GetNextIndex(indexInfoPtr)
  360.     register DirIndexInfo *indexInfoPtr; /* Index structure to set up. */
  361. {
  362.     int            accessible = 0;
  363.     register Fsdm_FileDescriptor    *fdPtr;
  364.  
  365.     fdPtr = indexInfoPtr->fdPtr;
  366.  
  367.     indexInfoPtr->blockNum++;
  368.     indexInfoPtr->dirDirty = 0;
  369.  
  370.     /*
  371.      * Determine whether we are now in direct, indirect or doubly indirect
  372.      * blocks.
  373.      */
  374.     switch (indexInfoPtr->indexType) {
  375.     case DIRECT:
  376.         if (indexInfoPtr->blockNum < FSDM_NUM_DIRECT_BLOCKS) {
  377.         /*
  378.          * Still in the direct blocks.
  379.          */
  380.         indexInfoPtr->firstIndex++;
  381.         indexInfoPtr->blockAddr = 
  382.                 fdPtr->direct[indexInfoPtr->firstIndex];
  383.         accessible = 1;
  384.         } else {
  385.         /*
  386.          * Moved into indirect blocks.
  387.          */
  388.         indexInfoPtr->indexType = INDIRECT;
  389.         indexInfoPtr->firstIndex = 0;
  390.         }
  391.         break;
  392.     case INDIRECT:
  393.         if (indexInfoPtr->blockNum < FSDM_NUM_DIRECT_BLOCKS +
  394.             FSDM_INDICES_PER_BLOCK) {
  395.         /*
  396.          * Still in singly indirect blocks.
  397.          */
  398.         indexInfoPtr->firstIndex++;
  399.         indexInfoPtr->blockAddr = *(int *) (indexInfoPtr->firstBlock +
  400.                   sizeof(int) * indexInfoPtr->firstIndex);
  401.         accessible = 1;
  402.         break;
  403.        } else {
  404.         /*
  405.          * Moved into doubly indirect blocks.
  406.          */
  407.         indexInfoPtr->firstIndex = 0;
  408.         indexInfoPtr->secondIndex = 0;
  409.         indexInfoPtr->indexType = DBL_INDIRECT;
  410.         /*
  411.          * Free up the pointer block.
  412.          */
  413.         indexInfoPtr->firstBlockNil = 1;
  414.         }
  415.         break;
  416.     case DBL_INDIRECT:
  417.         indexInfoPtr->secondIndex++;
  418.         if (indexInfoPtr->secondIndex == FSDM_INDICES_PER_BLOCK) {
  419.         indexInfoPtr->firstIndex++;
  420.         indexInfoPtr->secondIndex = 0;
  421.         indexInfoPtr->secondBlockNil = 1;
  422.         } else {
  423.         indexInfoPtr->blockAddr = *(int *) (indexInfoPtr->secondBlock +
  424.                   sizeof(int) * indexInfoPtr->secondIndex);
  425.         accessible = 1;
  426.         }
  427.         break;
  428.     }
  429.  
  430.     /*
  431.      * Make the block pointers accessible if necessary.
  432.      */
  433.     if (!accessible) {
  434.     return(MakePtrAccessible(indexInfoPtr));
  435.     } else {
  436.     return(1);
  437.     }
  438. }
  439.  
  440.  
  441. /*
  442.  *----------------------------------------------------------------------
  443.  *
  444.  * OpenDir --
  445.  *
  446.  *    Set up the structure to allow moving through the given directory.
  447.  *
  448.  * Results:
  449.  *    None.
  450.  *
  451.  * Side effects:
  452.  *    The index structure is set up and *dirEntryPtrPtr set to point to
  453.  *    the first directory entry.
  454.  *
  455.  *----------------------------------------------------------------------
  456.  */
  457. static void
  458. OpenDir(fdPtr, fdInfoPtr, indexInfoPtr, dirEntryPtrPtr)
  459.     Fsdm_FileDescriptor    *fdPtr;        /* The file descriptor for the
  460.                      * directory. */
  461.     FdInfo        *fdInfoPtr;    /* Descriptor status info for the
  462.                      * directory. */
  463.     DirIndexInfo     *indexInfoPtr;    /* Index info struct */
  464.     Fslcl_DirEntry        **dirEntryPtrPtr; /* Where to return a pointer to
  465.                        * the first directory entry. */
  466. {
  467.     int            fragsToRead;
  468.  
  469.     if (fdPtr->lastByte == -1) {
  470.     /*
  471.      * Empty directory.
  472.      */
  473.     *dirEntryPtrPtr = (Fslcl_DirEntry *) NULL;
  474.     return;
  475.     } else if ((fdPtr->lastByte + 1) % FSLCL_DIR_BLOCK_SIZE != 0) {
  476.     fprintf(stderr,
  477.     "Directory not multiple of directory block size. Directory corrected.\n");
  478.     foundError = 1;
  479.     fdPtr->lastByte = (fdPtr->lastByte & ~(FSLCL_DIR_BLOCK_SIZE - 1)) +
  480.                 FSLCL_DIR_BLOCK_SIZE - 1;
  481.     fdInfoPtr->flags |= FD_MODIFIED;
  482.     }
  483.     /*
  484.      * Initialize the index structure.
  485.      */
  486.     indexInfoPtr->fdPtr = fdPtr;
  487.     indexInfoPtr->fdInfoPtr = fdInfoPtr;
  488.     if (!GetFirstIndex(0, indexInfoPtr)) {
  489.     fprintf(stderr, "OpenDir: Error setting up index\n");
  490.     *dirEntryPtrPtr = (Fslcl_DirEntry *) NULL;
  491.     return;
  492.     }
  493.     /*
  494.      * Read in the first directory block.
  495.      */
  496.     if (fdPtr->lastByte >= FS_BLOCK_SIZE - 1) {
  497.     fragsToRead = FS_FRAGMENTS_PER_BLOCK;
  498.     } else {
  499.     fragsToRead = fdPtr->lastByte / FS_FRAGMENT_SIZE + 1;
  500.     }
  501.     indexInfoPtr->numFrags = fragsToRead;
  502.     if (DiskRead(diskFd, 
  503.               indexInfoPtr->blockAddr, 
  504.               fragsToRead*FS_FRAGMENT_SIZE, indexInfoPtr->dirBlock) 
  505.               != fragsToRead*FS_FRAGMENT_SIZE) {
  506.     fprintf(stderr, "OpenDir: Read failed block %d\n",
  507.                indexInfoPtr->blockAddr); 
  508.     *dirEntryPtrPtr = (Fslcl_DirEntry *) NULL;
  509.     return;
  510.     } 
  511.     indexInfoPtr->dirOffset = 0;
  512.     *dirEntryPtrPtr = (Fslcl_DirEntry *) indexInfoPtr->dirBlock;
  513. }
  514.  
  515.  
  516. /*
  517.  *----------------------------------------------------------------------
  518.  *
  519.  * NextDirEntry --
  520.  *
  521.  *    Return a pointer to the next directory entry.
  522.  *
  523.  * Results:
  524.  *    None.
  525.  *
  526.  * Side effects:
  527.  *    The index structure is modified and *dirEntryPtrPtr set to point
  528.  *    to the next directory entry.
  529.  *
  530.  *----------------------------------------------------------------------
  531.  */
  532. static void
  533. NextDirEntry(indexInfoPtr, dirEntryPtrPtr)
  534.     DirIndexInfo     *indexInfoPtr;
  535.     Fslcl_DirEntry        **dirEntryPtrPtr;
  536. {
  537.     int            firstDirByte;
  538.     int            lastByte;
  539.     Fslcl_DirEntry        *dirEntryPtr;
  540.     int            fragsToRead;
  541.  
  542.     dirEntryPtr = *dirEntryPtrPtr;
  543.     indexInfoPtr->dirOffset += dirEntryPtr->recordLength;
  544.     lastByte = indexInfoPtr->fdPtr->lastByte;
  545.     firstDirByte = 
  546.      indexInfoPtr->dirOffset + indexInfoPtr->blockNum * FS_BLOCK_SIZE;
  547.     if (firstDirByte == lastByte + 1) {
  548.     /*
  549.      * We reached the end of the directory.  Write out the directory
  550.      * block if necessary.
  551.      */
  552.     *dirEntryPtrPtr = (Fslcl_DirEntry *) NULL;
  553.     return;
  554.     }
  555.  
  556.     if (indexInfoPtr->dirOffset < FS_BLOCK_SIZE) {
  557.     /*
  558.      * The next directory entry is in the current block.
  559.      */
  560.     dirEntryPtr = 
  561.          (Fslcl_DirEntry *) &(indexInfoPtr->dirBlock[indexInfoPtr->dirOffset]);
  562.     } else {
  563.     /*
  564.      * Have to move to the next directory block.  Write out the current
  565.      * block if necessary.
  566.      */
  567.     if (indexInfoPtr->dirDirty) {
  568.         if (DiskWrite(diskFd,
  569.                   indexInfoPtr->blockAddr,
  570.                   indexInfoPtr->numFrags*FS_FRAGMENT_SIZE, 
  571.                   indexInfoPtr->dirBlock) != 
  572.                   indexInfoPtr->numFrags*FS_FRAGMENT_SIZE) {
  573.         fprintf(stderr, "NextDirEntry: Write (2) failed block %d\n",
  574.                    indexInfoPtr->blockAddr);
  575.         *dirEntryPtrPtr = (Fslcl_DirEntry *) NULL;
  576.         }
  577.     }
  578.     if (!GetNextIndex(indexInfoPtr)) {
  579.         fprintf(stderr, "NextDirEntry: Get index failed\n");
  580.         *dirEntryPtrPtr = (Fslcl_DirEntry *) NULL;
  581.         return;
  582.     }
  583.     if (lastByte - firstDirByte + 1 >= FS_BLOCK_SIZE ||
  584.         indexInfoPtr->blockNum >= FSDM_NUM_DIRECT_BLOCKS) {
  585.         fragsToRead = FS_FRAGMENTS_PER_BLOCK;
  586.     } else {
  587.         fragsToRead = (lastByte - firstDirByte) / FS_FRAGMENT_SIZE + 1;
  588.     }
  589.     indexInfoPtr->numFrags = fragsToRead;
  590.     if (DiskRead(diskFd,   indexInfoPtr->blockAddr,
  591.               fragsToRead*FS_FRAGMENT_SIZE, 
  592.               indexInfoPtr->dirBlock) != fragsToRead*FS_FRAGMENT_SIZE) {
  593.         fprintf(stderr, "NextDirEntry: Read failed block %d\n",
  594.                 indexInfoPtr->blockAddr); 
  595.         *dirEntryPtrPtr = (Fslcl_DirEntry *) NULL;
  596.         return;
  597.     }
  598.     indexInfoPtr->dirOffset = 0;
  599.     dirEntryPtr = (Fslcl_DirEntry *) indexInfoPtr->dirBlock;
  600.     }
  601.  
  602.     *dirEntryPtrPtr = dirEntryPtr;
  603. }
  604.  
  605. static    DirIndexInfo    lostDirIndex;
  606. static  Fslcl_DirEntry    *lostDirEntryPtr;
  607.  
  608. static    List_Links    orphanDirListHdr;
  609. static  List_Links    *orphanDirList = &orphanDirListHdr;
  610. typedef struct DirList {
  611.     List_Links    links;
  612.     int        dirNumber;
  613. } DirList;
  614.  
  615. /*
  616.  *----------------------------------------------------------------------
  617.  *
  618.  * CloseDir --
  619.  *
  620.  *    Flushes the current directory block to disk, if necessary.
  621.  *
  622.  * Results:
  623.  *    None.
  624.  *
  625.  * Side effects:
  626.  *    The index structure is modified and *dirEntryPtrPtr set to point
  627.  *    to the next directory entry.
  628.  *
  629.  *----------------------------------------------------------------------
  630.  */
  631. static void
  632. CloseDir(indexInfoPtr)
  633.     DirIndexInfo     *indexInfoPtr;
  634. {
  635.     if (indexInfoPtr->dirDirty) {
  636.     if (DiskWrite(diskFd,
  637.               indexInfoPtr->blockAddr,  
  638.               indexInfoPtr->numFrags * FS_FRAGMENT_SIZE, 
  639.               indexInfoPtr->dirBlock) != indexInfoPtr->numFrags * FS_FRAGMENT_SIZE) {
  640.         fprintf(stderr, "CloseDir: Write (2) failed block %d\n",
  641.                indexInfoPtr->blockAddr);
  642.         return;
  643.     }
  644.     }
  645. }
  646.  
  647.  
  648. /*
  649.  *----------------------------------------------------------------------
  650.  *
  651.  * CheckDirTree --
  652.  *
  653.  *    Traverse the directory tree taking care of unreferenced files and
  654.  *    ensuring that link counts are correct.
  655.  *
  656.  * Results:
  657.  *    A return status.
  658.  *
  659.  * Side effects:
  660.  *    None.
  661.  *
  662.  *----------------------------------------------------------------------
  663.  */
  664. void
  665. CheckDirTree(diskId)
  666.     int            diskId;
  667. {
  668.     register    int    i;
  669.     register FdInfo    *fdInfoPtr;
  670.     Fslcl_DirEntry        *dirEntryPtr;
  671.     DirIndexInfo    dirIndex;
  672.     int            lostRootDirNum = -1;
  673.     int            unrefFiles = 0;
  674.     int            linkCountsCorrected = 0;
  675.     int            entryNum;
  676.     int            notAdded;
  677.     char                newFileName[100];
  678.  
  679.  
  680.     List_Init(&modListHdr);
  681.     diskFd = diskId;
  682.     /*
  683.      * Check the root directory for consistency.
  684.      */
  685.     if (!FetchFileDesc(FSDM_ROOT_FILE_NUMBER, &rootFDPtr)) {
  686.     fprintf(stderr, "Unable to fetch file descriptor for root");
  687.     exit(EXIT_HARD_ERROR);
  688.     }
  689.  
  690.     if ((rootFDPtr->flags & FSDM_FD_FREE) ||
  691.     rootFDPtr->fileType != FS_DIRECTORY ||
  692.     rootFDPtr->magic != FSDM_FD_MAGIC ||
  693.     rootFDPtr->lastByte == -1) {
  694.  
  695.     fprintf(stderr, "Root directory corrupted. Will recreate\n");
  696. #ifdef PATCHROOT
  697.     fprintf(stderr, "Attempting to re-create the root\n");
  698.     lostRootDirNum = FSDM_ROOT_FILE_NUMBER;
  699.     List_Init(orphanDirList);
  700.     lostFoundFileNum = FSDM_ROOT_FILE_NUMBER + 1;
  701.     if (MakeRoot( rootFDPtr) != SUCCESS) {
  702.         fprintf(stderr,"Unable to reinitialize root fd.\n");
  703.         exit(EXIT_HARD_ERROR);
  704.     }
  705.     OpenDir(rootFDPtr, &descInfoArray[FSDM_ROOT_FILE_NUMBER], &rootDirIndex, 
  706.         &rootDirEntryPtr);
  707.     /*
  708.      * Create the "." and ".." entries in the trashed directory.  The
  709.      * above OpenDir call has set up rootDirEntryPtr to reference the
  710.      * first bytes in the directory.
  711.      */
  712.         descInfoArray[FSDM_ROOT_FILE_NUMBER].flags |= FD_ALLOCATED;
  713.     descInfoArray[FSDM_ROOT_FILE_NUMBER].flags |= FD_MODIFIED;
  714.     descInfoArray[FSDM_ROOT_FILE_NUMBER].flags |= IS_A_DIRECTORY;
  715.     StoreFileDesc(FSDM_ROOT_FILE_NUMBER, rootFDPtr);
  716.     fileName = ".";
  717.     rootDirEntryPtr->fileNumber = lostRootDirNum;
  718.     rootDirEntryPtr->nameLength = strlen(fileName);
  719.     rootDirEntryPtr->recordLength =
  720.         Fslcl_DirRecLength(rootDirEntryPtr->nameLength);
  721.     (void)strcpy(rootDirEntryPtr->fileName, fileName);
  722.     offset = rootDirEntryPtr->recordLength;
  723.     NextDirEntry(&rootDirIndex, &rootDirEntryPtr);
  724.  
  725.     fileName = "..";
  726.     rootDirEntryPtr->fileNumber = lostRootDirNum;
  727.     rootDirEntryPtr->nameLength = strlen(fileName);
  728.     rootDirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE - offset;
  729.     (void)strcpy(rootDirEntryPtr->fileName, fileName);
  730.     NextDirEntry(&rootDirIndex, &rootDirEntryPtr);
  731.     for(i = 1; i < FS_BLOCK_SIZE / FSLCL_DIR_BLOCK_SIZE; i++) {
  732.         rootDirEntryPtr->fileNumber = 0;
  733.         rootDirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE;
  734.         rootDirEntryPtr->nameLength = 0;
  735.         NextDirEntry(&rootDirIndex, &rootDirEntryPtr);
  736.     }
  737.     rootDirIndex.dirDirty = 1;
  738.     CloseDir(&rootDirIndex);
  739. #else
  740.     exit(EXIT_HARD_ERROR);
  741. #endif
  742.     }
  743.     OpenDir(rootFDPtr, &descInfoArray[FSDM_ROOT_FILE_NUMBER], &dirIndex, 
  744.         &dirEntryPtr);
  745.     if (dirEntryPtr == (Fslcl_DirEntry *)NULL) {
  746.     exit(EXIT_HARD_ERROR);
  747.     }
  748.  
  749.     (void)strcpy(pathName, "/");
  750.     entryNum = 0;
  751.     while (dirEntryPtr != (Fslcl_DirEntry *) NULL) {
  752.     /*
  753.      * Go through the root directory checking each directory entry.
  754.      */
  755.     CheckDirEntry(entryNum, &dirIndex, dirEntryPtr);
  756.     if (dirEntryPtr->nameLength > 0 && 
  757.         strncmp("lost+found", dirEntryPtr->fileName,
  758.             dirEntryPtr->nameLength)  == 0) {
  759.         lostFoundFileNum = dirEntryPtr->fileNumber;
  760.     }
  761.     NextDirEntry(&dirIndex, &dirEntryPtr);
  762.     entryNum++;
  763.     }
  764.     CloseDir(&dirIndex);
  765.     if (tooBig) {
  766.     return;
  767.     }
  768.  
  769.     if (lostFoundFileNum == -1) {
  770.     fprintf(stderr, "lost+found missing from root\n");
  771.     lostFoundFileNum = -1;
  772.     } else {
  773.     /*
  774.      * Make sure that lost and found is consistent.
  775.      */
  776.     if (!FetchFileDesc(lostFoundFileNum, &lostFoundFDPtr)) {
  777.         fprintf(stderr, "Unable to fetch file descriptor for lost+found");
  778.         exit(EXIT_HARD_ERROR);
  779.     }
  780.  
  781.     (void)strcpy(pathName, "/lost+found/");
  782.     fdInfoPtr = &descInfoArray[lostFoundFileNum];
  783.     if (lostFoundFDPtr->fileType != FS_DIRECTORY) {
  784.         fprintf(stderr,
  785.          "Lost+found isn't a directory!  Should remove and recreate.\n");
  786.         lostFoundFileNum = -1;
  787.     } else {
  788.         int    dirOK;
  789.  
  790.         CheckDir(lostFoundFileNum, lostFoundFDPtr, fdInfoPtr,
  791.             FSDM_ROOT_FILE_NUMBER, lostRootDirNum,    &dirOK);
  792.         if (dirOK) {
  793.         OpenDir(lostFoundFDPtr, fdInfoPtr, &lostDirIndex,
  794.                  &lostDirEntryPtr);
  795.         if (lostDirEntryPtr == (Fslcl_DirEntry *)NULL) {
  796.             fprintf(stderr, "Could not open lost+found\n");
  797.             lostFoundFileNum = -1;
  798.         } else {
  799.             descInfoArray[lostFoundFileNum].flags |= FD_SEEN;
  800.         }
  801.         } else {
  802.         lostFoundFileNum = -1;
  803.         }
  804.     }
  805.     }
  806.  
  807.     if (tooBig) {
  808.     return;
  809.     }
  810.     /*
  811.      * Check all file descriptors.  If we are re-creating the root this
  812.      * has a side-effect of preparing a list of the orphans of the root.
  813.      */
  814.     for (i = 0, fdInfoPtr = descInfoArray;
  815.      i < superBlockPtr->descMap.maxDesc; 
  816.      i++, fdInfoPtr++) {
  817.     int            dirOK;
  818.     Fsdm_FileDescriptor    *newFDPtr;
  819.  
  820.     if (!(fdInfoPtr->flags & FD_ALLOCATED) ||
  821.          (fdInfoPtr->flags & FD_SEEN) ||
  822.         !(fdInfoPtr->flags & IS_A_DIRECTORY)) {
  823.         continue;
  824.     }
  825.     pathName[0] = '\0';
  826.     if (!FetchFileDesc(i, &newFDPtr)) {
  827.         fprintf(stderr,
  828.             "Unable to fetch file descriptor for directory <%d>.\n", i);
  829.         continue;
  830.     }
  831.     CheckDir(i, newFDPtr, fdInfoPtr, FSDM_ROOT_FILE_NUMBER,
  832.         lostRootDirNum, &dirOK);
  833.     StoreFileDesc(i, newFDPtr);
  834.     }
  835. #ifdef PATCHROOT
  836.     if (patchRoot && lostRootDirNum > 0) {
  837.     DirList *dirListPtr;
  838.  
  839.     notAdded = 0;
  840.  
  841.     /*
  842.      * Go through the list of root-orphans, putting them into the root.
  843.      */
  844.     OpenDir(rootFDPtr, &descInfoArray[FSDM_ROOT_FILE_NUMBER], &rootDirIndex, 
  845.         &rootDirEntryPtr);
  846.  
  847.     LIST_FORALL(orphanDirList, (List_Links *)dirListPtr) {
  848.         if (dirListPtr->dirNumber == lostFoundFileNum) {
  849.         (void) strncpy(newFileName,"lost+found",100);
  850.         } else { 
  851.         (void) sprintf(newFileName, "%d", dirListPtr->dirNumber);
  852.         }
  853.         if (AddToDirectory(lostRootDirNum, rootFDPtr, &rootDirIndex,
  854.              &rootDirEntryPtr, dirListPtr->dirNumber,
  855.              newFileName,
  856.              &descInfoArray[dirListPtr->dirNumber]) == DIRFULL) {
  857.         if (notAdded == 0) {
  858.             fprintf(stderr, 
  859.             "Directory #%d full.  Couldn't insert file.\n", 
  860.             lostRootDirNum);
  861.         }
  862.         notAdded++;
  863.         }
  864.     }
  865.     if (notAdded > 0) {
  866.         fprintf(stderr, "%d files not added to directory %d.\n", notAdded,
  867.         lostRootDirNum);
  868.     }
  869.     if (rootDirIndex.dirDirty) {
  870.         if (DiskWrite(diskFd, 
  871.                 rootDirIndex.blockAddr,
  872.                 rootDirIndex.numFrags * FS_FRAGMENT_SIZE, 
  873.                 rootDirIndex.dirBlock) != 
  874.                 rootDirIndex.numFrags * FS_FRAGMENT_SIZE) {
  875.         fprintf(stderr, "CheckDirTree: Write failed");
  876.         exit(EXIT_WRITE_FAILURE);
  877.         }
  878.     }
  879.     }
  880.     if (tooBig) {
  881.     return;
  882.     }
  883. #endif
  884.     /*
  885.      * Now go through the file descriptors again this time putting all
  886.      * unreferenced files in the lost and found directory and correcting
  887.      * link counts.
  888.      */
  889.     notAdded = 0;
  890.     for (i = 0, fdInfoPtr = descInfoArray;
  891.      i < superBlockPtr->descMap.maxDesc; 
  892.      i++, fdInfoPtr++) {
  893.  
  894.     /*
  895.      * We have to do lost+found last because its link count is changed
  896.      * when directories are added to it.
  897.      */
  898.  
  899.     if (i == lostFoundFileNum) {
  900.         continue;
  901.     } else if (i == superBlockPtr->descMap.maxDesc-1) {
  902.         if (lostFoundFileNum == -1) {
  903.         break;
  904.         }
  905.         i = lostFoundFileNum;
  906.         fdInfoPtr = &descInfoArray[lostFoundFileNum];
  907.     }
  908.     if (!(fdInfoPtr->flags & FD_ALLOCATED) ||
  909.         (fdInfoPtr->flags & FD_UNREADABLE) ||
  910.         i == FSDM_BAD_BLOCK_FILE_NUMBER) {
  911.         continue;
  912.     }
  913.  
  914.     if (!(fdInfoPtr->flags & FD_REFERENCED) && i != FSDM_ROOT_FILE_NUMBER) {
  915.         if (verbose) {
  916.         fprintf(stderr, "File %d is unreferenced\n", i);
  917.         }
  918.         unrefFiles++;
  919.         foundError = 1;
  920.         fflush(stderr);
  921.         if (lostFoundFileNum != -1) {
  922.         (void) sprintf(newFileName,"%d",i);
  923.  
  924.         if (AddToDirectory(lostFoundFileNum, lostFoundFDPtr, 
  925.                 &lostDirIndex, &lostDirEntryPtr, i, 
  926.                 newFileName, fdInfoPtr) == DIRFULL) {
  927.             if (notAdded == 0) {
  928.             fprintf(stderr, 
  929.                 "Directory #%d full.  Couldn't insert file.\n", 
  930.                 lostFoundFileNum);
  931.             }
  932.             notAdded++;
  933.         }
  934.         }
  935.     } else if (fdInfoPtr->newLinkCount != fdInfoPtr->origLinkCount) {
  936.         if (verbose) {
  937.         fprintf(stderr,
  938.             "Link count corrected for file %d.  Is %d should be %d.\n", 
  939.             i, fdInfoPtr->origLinkCount, fdInfoPtr->newLinkCount);
  940.         }
  941.         linkCountsCorrected++;
  942.         foundError = 1;
  943.         fflush(stderr);
  944.         if (i == FSDM_ROOT_FILE_NUMBER) {
  945.         rootFDPtr->numLinks = fdInfoPtr->newLinkCount;
  946.         fdInfoPtr->flags |= FD_MODIFIED;
  947.         } else if (i == lostFoundFileNum) {
  948.         lostFoundFDPtr->numLinks = fdInfoPtr->newLinkCount;
  949.         fdInfoPtr->flags |= FD_MODIFIED;
  950.         } else {
  951.         Fsdm_FileDescriptor    *fdPtr;
  952.         if (!FetchFileDesc(i, &fdPtr)) {
  953.             fprintf(stderr,
  954.       "Unable to fetch file descriptor for file <%d> to update link count", i);
  955.         } else {
  956.             fdPtr->numLinks = fdInfoPtr->newLinkCount;
  957.             fdInfoPtr->flags |= FD_MODIFIED;
  958.             StoreFileDesc(i, fdPtr);
  959.         }
  960.         }
  961.     }
  962.     if (i == lostFoundFileNum) {
  963.         break;
  964.     }
  965.     }
  966.     if (notAdded > 0) {
  967.     fprintf(stderr, "%d files not added to directory %d.\n", notAdded,
  968.         lostFoundFileNum);
  969.     }
  970.  
  971.     if (unrefFiles > 0) {
  972.     fprintf(stderr, "%d unreferenced files\n", unrefFiles);
  973.     }
  974.     if (linkCountsCorrected) {
  975.     fprintf(stderr, "%d links counts corrected\n",
  976.                linkCountsCorrected);
  977.     }
  978.  
  979.     if (lostFoundFileNum != - 1 && lostDirIndex.dirDirty) {
  980.     if (DiskWrite(diskFd,
  981.             lostDirIndex.blockAddr,
  982.                 lostDirIndex.numFrags * FS_FRAGMENT_SIZE, 
  983.                 lostDirIndex.dirBlock) != 
  984.             lostDirIndex.numFrags * FS_FRAGMENT_SIZE) {
  985.         fprintf(stderr, "CheckDirTree: Write failed");
  986.         exit(EXIT_WRITE_FAILURE);
  987.     }
  988.     }
  989.  
  990.     StoreFileDesc(FSDM_ROOT_FILE_NUMBER, rootFDPtr);
  991.     if (lostFoundFileNum != -1) {
  992.     StoreFileDesc(lostFoundFileNum, lostFoundFDPtr);
  993.     }
  994.     WriteModDescs(diskId);
  995. }
  996.  
  997.  
  998. /*
  999.  *----------------------------------------------------------------------
  1000.  *
  1001. * CheckDir --
  1002.  *
  1003.  *    Descend the directory tree starting from the given file descriptor.
  1004.  *
  1005.  * Results:
  1006.  *    None.
  1007.  *
  1008.  * Side effects:
  1009.  *    None.
  1010.  *
  1011.  *----------------------------------------------------------------------
  1012.  */
  1013.  
  1014. static void
  1015. CheckDir(fdNum, fdPtr, fdInfoPtr, parentFdNum, lostDirNum, dirOKPtr)
  1016.     int            fdNum;    /* Which file descriptor we are looking
  1017.                        at. */
  1018.     Fsdm_FileDescriptor    *fdPtr;        /* Pointer the file descriptor that
  1019.                      * we are looking at. */
  1020.     FdInfo        *fdInfoPtr;    /* Status of the file desc that we are
  1021.                        looking at. */
  1022.     int            parentFdNum;    /* File descriptor of parent directory.
  1023.                      */
  1024.     int            lostDirNum;    /* For re-creating trashed directories.
  1025.                      * This routine will add to a list
  1026.                      * of directories that were ref'ed
  1027.                      * by this 'lost directory' */
  1028.     int            *dirOKPtr;    /* Return 1 if the directory is
  1029.                      * not corrupted. */
  1030. {
  1031.     Fslcl_DirEntry     *dirEntryPtr;
  1032.     FdInfo     *newFDInfoPtr;
  1033.     DirIndexInfo dirIndex;
  1034.     int         entryNum;
  1035.     int        nullIndex;
  1036.  
  1037.     fdInfoPtr->flags |= FD_SEEN;
  1038.     *dirOKPtr = 0;
  1039.  
  1040.     /*
  1041.      * Open the directory.
  1042.      */
  1043.     OpenDir(fdPtr, fdInfoPtr, &dirIndex, &dirEntryPtr);
  1044.     nullIndex = strlen(pathName);
  1045.     if (dirEntryPtr == (Fslcl_DirEntry *) NULL) {    
  1046.     fprintf(stderr, "Empty directory %d %s changed to a file.\n",
  1047.                 fdNum, pathName);
  1048.     foundError = 1;
  1049.     fdPtr->fileType = FS_FILE;
  1050.     fdInfoPtr->flags |= FD_MODIFIED;
  1051.     return;
  1052.     }
  1053.     /*
  1054.      * Go through the directory.
  1055.      */
  1056.     entryNum = 0;
  1057.     if (debug) {
  1058.     fprintf(stderr,"Working on %s\n",pathName);
  1059.     }
  1060.     do {
  1061.     CheckDirEntry(entryNum, &dirIndex, dirEntryPtr);
  1062.     if (entryNum == 0) {
  1063.         /*
  1064.          * This should be "." and should point to the directory that
  1065.          * we are checking.
  1066.          */
  1067.         if (dirEntryPtr->fileNumber == 0 ||
  1068.         strncmp(".", dirEntryPtr->fileName, 
  1069.             dirEntryPtr->nameLength)  != 0) {
  1070.         fprintf(stderr,
  1071.             ". missing in directory %d %s.  Changed to a file.\n",
  1072.                    fdNum, pathName);
  1073.         foundError = 1;
  1074.         fdPtr->fileType = FS_FILE;
  1075.         fdInfoPtr->flags |= FD_MODIFIED;
  1076.         fdInfoPtr->flags &= ~IS_A_DIRECTORY;
  1077.         return;
  1078.         }
  1079.         if (dirEntryPtr->fileNumber != fdNum) {
  1080.         fprintf(stderr, 
  1081.                 ". does not point to self for directory %d %s\n",
  1082.                 fdNum, pathName);
  1083.         foundError = 1;
  1084.         dirEntryPtr->fileNumber = fdNum;
  1085.         dirIndex.dirDirty = 1;
  1086.         }
  1087.         fdInfoPtr->newLinkCount++;
  1088.     } else if (entryNum == 1) {
  1089.         /*
  1090.          * This should be ".."
  1091.          */
  1092.         if (dirEntryPtr->fileNumber == 0 ||
  1093.         strncmp("..", dirEntryPtr->fileName, 
  1094.             dirEntryPtr->nameLength) != 0) {
  1095.         fprintf(stderr,
  1096.             ".. missing in directory %d %s.  Changed to a file.\n",
  1097.                    fdNum, pathName);
  1098.         foundError = 1;
  1099.         fdPtr->fileType = FS_FILE;
  1100.         fdInfoPtr->flags |= FD_MODIFIED;
  1101.         fdInfoPtr->flags &= ~IS_A_DIRECTORY;
  1102.         return;
  1103.         }
  1104.         if (dirEntryPtr->fileNumber != parentFdNum) {
  1105.         fprintf(stderr, 
  1106.             ".. in directory %d %s pointed to %d, changed to %d.\n",
  1107.             fdNum, pathName, dirEntryPtr->fileNumber, parentFdNum);
  1108.         foundError = 1;
  1109.         dirEntryPtr->fileNumber = parentFdNum;
  1110.         dirIndex.dirDirty = 1;
  1111.         }
  1112.         /*
  1113.          * Look for orphans of lost directories.
  1114.          */
  1115.         if (lostDirNum > 0 &&
  1116.         dirEntryPtr->fileNumber == lostDirNum &&
  1117.         (fdNum != FSDM_ROOT_FILE_NUMBER ||
  1118.         lostDirNum != FSDM_ROOT_FILE_NUMBER)) {
  1119.         DirList *dirListPtr;
  1120.         Alloc(dirListPtr,DirList,1);
  1121.         if (!tooBig) {
  1122.             dirListPtr->dirNumber = fdNum;
  1123.             fprintf(stderr, "Found #%d, an orphan of dir #%d\n", 
  1124.                 fdNum, lostDirNum);
  1125.             List_Insert((List_Links *)dirListPtr,
  1126.                 LIST_ATREAR(orphanDirList));
  1127.             fdInfoPtr->flags |= FD_REFERENCED;
  1128.             fdInfoPtr->newLinkCount++;
  1129.         }
  1130.         } else {
  1131.         descInfoArray[dirEntryPtr->fileNumber].newLinkCount++;
  1132.         }
  1133.     } else if (dirEntryPtr->fileNumber != 0) {
  1134.         newFDInfoPtr = &descInfoArray[dirEntryPtr->fileNumber];
  1135.         newFDInfoPtr->newLinkCount++;
  1136.         newFDInfoPtr->flags |= FD_REFERENCED;
  1137.         if (!(newFDInfoPtr->flags & FD_SEEN) &&
  1138.            (newFDInfoPtr->flags & IS_A_DIRECTORY)) {
  1139.         int    dirOK;
  1140.         Fsdm_FileDescriptor    *newFDPtr;
  1141.  
  1142.         /*
  1143.          * Recurse on the directory.
  1144.          */
  1145.         (void)strncat(pathName, dirEntryPtr->fileName,
  1146.                   dirEntryPtr->nameLength);
  1147.         (void)strcat(pathName, "/");
  1148.         if (!FetchFileDesc(dirEntryPtr->fileNumber, &newFDPtr)) {
  1149.             fprintf(stderr,
  1150.             "Unable to fetch file descriptor for directory <%d>.\n",
  1151.                   dirEntryPtr->fileNumber);
  1152.         } else {
  1153.             CheckDir(dirEntryPtr->fileNumber, newFDPtr, 
  1154.                  newFDInfoPtr, fdNum, lostDirNum, &dirOK);
  1155.             pathName[nullIndex] = '\0';
  1156.             StoreFileDesc(dirEntryPtr->fileNumber, newFDPtr);
  1157.         }
  1158.         } 
  1159.     }
  1160.     NextDirEntry(&dirIndex, &dirEntryPtr);
  1161.     entryNum++;
  1162.     } while (dirEntryPtr != (Fslcl_DirEntry *) NULL);
  1163.  
  1164.     *dirOKPtr = 1;
  1165. }
  1166.  
  1167.  
  1168. /*
  1169.  *----------------------------------------------------------------------
  1170.  *
  1171.  * CheckDirEntry --
  1172.  *
  1173.  *    Perform checks on the current directory entry to make sure that
  1174.  *    it is has not been trashed.
  1175.  *
  1176.  * Results:
  1177.  *    None.
  1178.  *
  1179.  * Side effects:
  1180.  *    The directory may be modified.
  1181.  *
  1182.  *----------------------------------------------------------------------
  1183.  */
  1184.  
  1185. void
  1186. CheckDirEntry(entryNum, dirIndexPtr, dirEntryPtr)
  1187.     int        entryNum;    
  1188.     register    DirIndexInfo    *dirIndexPtr;
  1189.     register    Fslcl_DirEntry    *dirEntryPtr;
  1190. {
  1191.     int            dirBlockOffset;
  1192.     int            lastDirByte;
  1193.     char        buf[FS_MAX_NAME_LENGTH + 1];
  1194.     int            nameLength;
  1195.     register    char    *strPtr;
  1196.     int hadError = 0;
  1197.  
  1198.     dirBlockOffset = dirIndexPtr->dirOffset & (FSLCL_DIR_BLOCK_SIZE - 1);
  1199.     lastDirByte = dirBlockOffset + dirEntryPtr->recordLength;
  1200.  
  1201.     if (dirEntryPtr->fileNumber == 0) {
  1202.     nameLength = 0;
  1203.     } else {
  1204.     nameLength = dirEntryPtr->nameLength;
  1205.     }
  1206.  
  1207.     /*
  1208.      * First check the record length.
  1209.      */
  1210.     if (lastDirByte > FSLCL_DIR_BLOCK_SIZE ||
  1211.     lastDirByte % FSLCL_REC_LEN_GRAIN != 0 || 
  1212.     (FSLCL_DIR_BLOCK_SIZE - lastDirByte < FSLCL_DIR_ENTRY_HEADER &&
  1213.      lastDirByte != FSLCL_DIR_BLOCK_SIZE) ||
  1214.     dirEntryPtr->recordLength < Fslcl_DirRecLength(nameLength) ||
  1215.     dirEntryPtr->recordLength < 0) {
  1216.     fprintf(stderr,
  1217.     "Bad record length in directory.  Directory entry deleted from %s\n",
  1218.                pathName);
  1219.     foundError = 1;
  1220.     hadError = 1;
  1221.     /*
  1222.      * If the record length is screwed up, extend this record to the end
  1223.      * of the directory block and zap the file number.
  1224.      */
  1225.     dirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE - dirBlockOffset;
  1226.     dirEntryPtr->fileNumber = 0;
  1227.     dirIndexPtr->dirDirty = 1;
  1228.     return;
  1229.     }
  1230.     /*
  1231.      * Check the name length.
  1232.      */
  1233.     if (dirEntryPtr->fileNumber != 0) {
  1234.     int    nameError = 0;
  1235.     nameLength = strnlen(dirEntryPtr->fileName,
  1236.                  dirEntryPtr->recordLength - FSLCL_DIR_ENTRY_HEADER);
  1237.     if (nameLength != dirEntryPtr->nameLength) {
  1238.         bcopy(dirEntryPtr->fileName, buf, nameLength);
  1239.         buf[nameLength] = '\0';
  1240.         fprintf(stderr,
  1241.         "Name length %d wrong for directory entry: %s. Should be %d.\n", 
  1242.         dirEntryPtr->nameLength, buf, nameLength);
  1243.         foundError = 1;
  1244.         hadError = 1;
  1245.         dirEntryPtr->nameLength = nameLength;
  1246.         dirIndexPtr->dirDirty = 1;
  1247.         dirEntryPtr->recordLength = Fslcl_DirRecLength(nameLength);
  1248.     }
  1249.     /*
  1250.      * Make sure that the name contains printable characters.
  1251.      */
  1252.     strPtr = dirEntryPtr->fileName;
  1253.     while (*strPtr != '\0') {
  1254.         if (*strPtr < 0 || !isprint(*strPtr)) {
  1255.         *strPtr = '?';
  1256.         nameError = 1;
  1257.         }
  1258.         strPtr++;
  1259.     }
  1260.     if (nameError) {
  1261.         dirIndexPtr->dirDirty = 1;
  1262.         fprintf(stderr,
  1263.           "Non-printable characters in name for file %d in directory %s\n",
  1264.           dirEntryPtr->fileNumber, pathName);
  1265.         foundError = 1;
  1266.         hadError = 1;
  1267.     }
  1268.     }
  1269.  
  1270.     /*
  1271.      * Now check the file number.
  1272.      */
  1273.     if (dirEntryPtr->fileNumber < 0 ||
  1274.         dirEntryPtr->fileNumber >= superBlockPtr->descMap.maxDesc) {
  1275.     fprintf(stderr, 
  1276.     "Bad file number in directory.  Directory entry deleted from %s.\n", 
  1277.                pathName);
  1278.     foundError = 1;
  1279.     hadError = 1;
  1280.     dirEntryPtr->fileNumber = 0;
  1281.     dirIndexPtr->dirDirty = 1;
  1282.     /*
  1283.      * Here we want to allow the ".." entry (entryNum = 0) to reference a
  1284.      * non-allocated file descriptor. What we have is an orphan directory so
  1285.      * we shouldn't nuke it just because something bad happened to its parent.
  1286.      */
  1287.     } else if (dirEntryPtr->fileNumber != 0 &&
  1288.               !(descInfoArray[dirEntryPtr->fileNumber].flags & FD_ALLOCATED) &&
  1289.           entryNum != 1)
  1290.           {
  1291.     fprintf(stderr, 
  1292.         "File %s%s references non-allocated descriptor %d. File Deleted.\n",
  1293.         pathName, dirEntryPtr->fileName,dirEntryPtr->fileNumber);
  1294.     foundError = 1;
  1295.     hadError = 1;
  1296.     dirEntryPtr->fileNumber = 0;
  1297.     dirIndexPtr->dirDirty = 1;
  1298.     }
  1299.     if (!hadError && debug) {
  1300.     fprintf(stderr,"Entry %s ok.\n",dirEntryPtr->fileName);
  1301.     }
  1302.     if (hadError) {
  1303.     fprintf(stderr,
  1304.     "Entry %s (%d) now has nameLength %d, recordLength %d, fileNumber %d.\n",
  1305.     dirEntryPtr->fileName, entryNum, dirEntryPtr->nameLength, 
  1306.     dirEntryPtr->recordLength, dirEntryPtr->fileNumber);
  1307.     }
  1308. }
  1309.  
  1310.  
  1311. /*
  1312.  *----------------------------------------------------------------------
  1313.  *
  1314.  * SetDotDot --
  1315.  *
  1316.  *    Make ".." in the given directory point to a given directory.
  1317.  *
  1318.  * Results:
  1319.  *    None.
  1320.  *
  1321.  * Side effects:
  1322.  *    ".." in the given directory is set to point to lost and found.
  1323.  *
  1324.  *----------------------------------------------------------------------
  1325.  */
  1326. static int
  1327. SetDotDot(dirNumber, dirFDPtr, fdPtr, fdInfoPtr)
  1328.     int            dirNumber;
  1329.     Fsdm_FileDescriptor    *dirFDPtr;
  1330.     Fsdm_FileDescriptor    *fdPtr;
  1331.     FdInfo        *fdInfoPtr;
  1332. {
  1333.     Fslcl_DirEntry         *dirEntryPtr;
  1334.     DirIndexInfo     dirIndex;
  1335.  
  1336.     /*
  1337.      * Open the directory.
  1338.      */
  1339.     OpenDir(fdPtr, fdInfoPtr, &dirIndex, &dirEntryPtr);
  1340.     if (dirEntryPtr == (Fslcl_DirEntry *)NULL) {
  1341.     fprintf(stderr, "SetDotDot: Could not open dir\n");
  1342.     return(0);
  1343.     }
  1344.     /*
  1345.      * Move past "." to "..".  Note that it is assume that this directory
  1346.      * has been checked and thus has both "." and "..".
  1347.      */
  1348.     NextDirEntry(&dirIndex, &dirEntryPtr);
  1349.     if (dirEntryPtr == (Fslcl_DirEntry *)NULL) {
  1350.     fprintf(stderr, "SetDotDot: Could not move from . to ..\n");
  1351.     return(0);
  1352.     }
  1353.  
  1354.     descInfoArray[dirNumber].newLinkCount++;
  1355.     descInfoArray[dirNumber].flags |= FD_MODIFIED;
  1356.     dirEntryPtr->fileNumber = dirNumber;
  1357.     if (DiskWrite(diskFd, 
  1358.        dirIndex.blockAddr,
  1359.        dirIndex.numFrags * FS_FRAGMENT_SIZE, dirIndex.dirBlock) != 
  1360.        dirIndex.numFrags * FS_FRAGMENT_SIZE) {
  1361.     fprintf(stderr, "SetDotDot: Write failed block %d\n",
  1362.         dirIndex.blockAddr);
  1363.     return(0);
  1364.     }
  1365.     return(1);
  1366. }
  1367.  
  1368. /*
  1369.  *----------------------------------------------------------------------
  1370.  *
  1371.  * AddToDirectory --
  1372.  *
  1373.  *    Add the file descriptor to a directory.  
  1374.  *
  1375.  * Results:
  1376.  *    None.
  1377.  *
  1378.  * Side effects:
  1379.  *    The directory is modified to contain the orphaned file.
  1380.  *
  1381.  *----------------------------------------------------------------------
  1382.  */
  1383. static ReturnStatus
  1384. AddToDirectory(dirNumber, dirFDPtr, dirIndexPtr, dirEntryPtrPtr, fileNumber,
  1385.     fileName, fdInfoPtr)
  1386.     int            dirNumber;
  1387.     Fsdm_FileDescriptor    *dirFDPtr;
  1388.     DirIndexInfo    *dirIndexPtr;
  1389.     Fslcl_DirEntry        **dirEntryPtrPtr;
  1390.     int             fileNumber;
  1391.     char         *fileName;
  1392.     register    FdInfo    *fdInfoPtr;
  1393. {
  1394.     int             nameLength;
  1395.     int             recordLength;
  1396.     int             leftOver;
  1397.     int            oldRecLength;
  1398.     Fslcl_DirEntry        *dirEntryPtr;
  1399.     Fsdm_FileDescriptor    *fdPtr;
  1400.  
  1401.     nameLength = strlen(fileName);
  1402.     recordLength = Fslcl_DirRecLength(nameLength);
  1403.  
  1404.     dirEntryPtr = *dirEntryPtrPtr;
  1405.     while (dirEntryPtr != (Fslcl_DirEntry *) NULL) {
  1406.     if (dirEntryPtr->fileNumber != 0) {
  1407.         oldRecLength = Fslcl_DirRecLength(dirEntryPtr->nameLength);
  1408.         leftOver = dirEntryPtr->recordLength - oldRecLength;
  1409.         if (leftOver >= recordLength) {
  1410.         dirEntryPtr->recordLength = oldRecLength;
  1411.         dirEntryPtr = 
  1412.             (Fslcl_DirEntry *) ((int) dirEntryPtr + oldRecLength);
  1413.         dirEntryPtr->recordLength = leftOver;
  1414.         dirIndexPtr->dirOffset += oldRecLength;
  1415.         } else {
  1416.         NextDirEntry(dirIndexPtr, &dirEntryPtr);
  1417.         continue;
  1418.         }
  1419.     } else if (dirEntryPtr->recordLength < recordLength) {
  1420.         NextDirEntry(dirIndexPtr, &dirEntryPtr);
  1421.         continue;
  1422.     }
  1423.  
  1424.     if (!FetchFileDesc(fileNumber, &fdPtr)) {
  1425.         fprintf(stderr,
  1426.      "Unable to fetch file descriptor for file <%d> to add to directory <%d>\n",
  1427.               fileNumber, dirNumber);
  1428.         return FAILURE;
  1429.     }
  1430.     if (fdInfoPtr->flags & IS_A_DIRECTORY) {
  1431.         if (!SetDotDot(dirNumber, dirFDPtr, fdPtr, fdInfoPtr)) {
  1432.         *dirEntryPtrPtr = dirEntryPtr;
  1433.         return FAILURE;
  1434.         }
  1435.     }
  1436.     fdPtr->numLinks = fdInfoPtr->newLinkCount + 1;
  1437.     fdInfoPtr->flags |= FD_MODIFIED;
  1438.     StoreFileDesc(fileNumber, fdPtr);
  1439.  
  1440.     dirEntryPtr->fileNumber = fileNumber;
  1441.     dirEntryPtr->nameLength = nameLength;
  1442.     dirIndexPtr->dirDirty = 1;
  1443.     (void)strcpy(dirEntryPtr->fileName, fileName);
  1444.     leftOver = dirEntryPtr->recordLength - recordLength;
  1445.     if (leftOver > FSLCL_DIR_ENTRY_HEADER) {
  1446.         dirEntryPtr->recordLength = recordLength;
  1447.         dirEntryPtr =(Fslcl_DirEntry *) ((int) dirEntryPtr + recordLength);
  1448.         dirEntryPtr->fileNumber = 0;
  1449.         dirEntryPtr->recordLength = leftOver;
  1450.         dirIndexPtr->dirOffset += recordLength;
  1451.     } else {
  1452.         NextDirEntry(dirIndexPtr, &dirEntryPtr);
  1453.     }
  1454.     *dirEntryPtrPtr = dirEntryPtr;
  1455.     return SUCCESS;
  1456.     }
  1457.     return DIRFULL;
  1458. }
  1459. #ifdef PATCHROOT
  1460.  
  1461. /*
  1462.  *----------------------------------------------------------------------
  1463.  *
  1464.  * MakeRoot --
  1465.  *
  1466.  *    Set up the file descriptor for the root directory.
  1467.  *
  1468.  * Results:
  1469.  *    Fill in the file descriptor.
  1470.  *
  1471.  * Side effects:
  1472.  *    Marks block 0 in the bitmap as in use.
  1473.  *
  1474.  *----------------------------------------------------------------------
  1475.  */
  1476. ReturnStatus
  1477. MakeRoot(fdPtr)
  1478.     Fsdm_FileDescriptor        *fdPtr;
  1479. {
  1480.     Time     time;
  1481.     int     index;
  1482.     u_char     *bytePtr;
  1483.  
  1484.     fdPtr->flags = FSDM_FD_ALLOC;
  1485.     fdPtr->fileType = FS_DIRECTORY;
  1486.     fdPtr->permissions = 0755;
  1487.     fdPtr->uid = 0;
  1488.     fdPtr->gid = 0;
  1489.     fdPtr->lastByte = FS_BLOCK_SIZE-1;
  1490.     fdPtr->firstByte = -1;
  1491.     fdPtr->numLinks = 3;
  1492.     /*
  1493.      * Can't know device information because that depends on
  1494.      * the way the system is configured.
  1495.      */
  1496.     fdPtr->devServerID  -1;
  1497.     fdPtr->devType = -1;
  1498.     fdPtr->devUnit = -1;
  1499.  
  1500.     /*
  1501.      * Set the time stamps.  This assumes that universal time, not local
  1502.      * time, is used for time stamps.
  1503.      */
  1504.     Sys_GetTimeOfDay(&time, NULL, NULL);
  1505.     fdPtr->createTime = time.seconds;
  1506.     fdPtr->accessTime = 0;
  1507.     fdPtr->descModifyTime = time.seconds;
  1508.     fdPtr->dataModifyTime = time.seconds;
  1509.  
  1510.     /*
  1511.      * Place the data in the first filesystem block.
  1512.      */
  1513.     fdPtr->direct[0] = superBlockPtr->hdr.logStartOffset;
  1514.     for (index = 1; index < FSDM_NUM_DIRECT_BLOCKS ; index++) {
  1515.     fdPtr->direct[index] = FSDM_NIL_INDEX;
  1516.     }
  1517.     for (index = 0; index < FSDM_NUM_INDIRECT_BLOCKS ; index++) {
  1518.     fdPtr->indirect[index] = FSDM_NIL_INDEX;
  1519.     }
  1520.     fdPtr->numKbytes = 4;
  1521.     fdPtr->version = 1;
  1522.     return SUCCESS;
  1523. }
  1524. #endif
  1525.  
  1526. /*
  1527.  *----------------------------------------------------------------------
  1528.  *
  1529.  * strnlen --
  1530.  *
  1531.  *    This is identical to strlen except that it will return N
  1532.  *    if the string length reaches N.
  1533.  *
  1534.  * Results:
  1535.  *    The return value is the number of characters in the
  1536.  *    string, not including the terminating zero byte.
  1537.  *
  1538.  * Side effects:
  1539.  *    None.
  1540.  *
  1541.  *----------------------------------------------------------------------
  1542.  */
  1543. int
  1544. strnlen(string, numChars)
  1545.     register char *string;        /* String whose length is wanted. */
  1546.     int           numChars;        /* Maximum number of chars to check. */
  1547. {
  1548.     register int result = -1;
  1549.  
  1550.     do {
  1551.     result += 1;
  1552.     } while (result < numChars && *string++ != 0);
  1553.     return(result);
  1554. }
  1555.  
  1556. /*
  1557.  *----------------------------------------------------------------------
  1558.  *
  1559.  * WriteFileDesc --
  1560.  *
  1561.  *    Write the file descriptors to disk.
  1562.  *
  1563.  * Results:
  1564.  *    None.
  1565.  *
  1566.  * Side effects:
  1567.  *    File descriptors on the modified list are all written to disk.
  1568.  *
  1569.  *----------------------------------------------------------------------
  1570.  */
  1571. static void
  1572. WriteModDescs(diskId)
  1573.     int     diskId;    /* Raw handle for disk. */
  1574.  
  1575. {
  1576.     int bufSize,  j;
  1577.     LfsFileDescriptor    *descPtr;
  1578.     char *descBuf;
  1579.     LfsDescMapEntry *descMapPtr;
  1580.     ModListElement    *modElemPtr;
  1581.  
  1582.     bufSize = superBlockPtr->fileLayout.descPerBlock * sizeof(*descPtr);
  1583.  
  1584.     descBuf = alloca(bufSize);
  1585.  
  1586.     LIST_FORALL(modList, (List_Links *)modElemPtr) {
  1587.     descMapPtr = DescMapEntry(modElemPtr->fdNum);
  1588.     if (DiskRead(diskFd, descMapPtr->blockAddress, bufSize, descBuf)
  1589.             != bufSize) {
  1590.         fprintf(stderr,"Can't read descriptor block at %d\n", 
  1591.                 descMapPtr->blockAddress);
  1592.         continue;
  1593.  
  1594.     }
  1595.     descPtr = (LfsFileDescriptor *)descBuf;
  1596.     for (j = 0; j < superBlockPtr->fileLayout.descPerBlock; j++) {
  1597.         if (!(descPtr->common.flags & FSDM_FD_ALLOC)) {
  1598.         break;
  1599.         }
  1600.         if (descPtr->fileNumber == modElemPtr->fdNum) {
  1601.         break;
  1602.         }
  1603.         descPtr++;
  1604.     }
  1605.     if ((j >= superBlockPtr->fileLayout.descPerBlock) ||
  1606.         !(descPtr->common.flags & FSDM_FD_ALLOC) ||
  1607.         (descPtr->fileNumber != modElemPtr->fdNum)) {
  1608.         fprintf(stderr,"Can't find descriptor %s at %d\n", 
  1609.                     modElemPtr->fdNum,
  1610.                     descMapPtr->blockAddress);
  1611.         continue;
  1612.     
  1613.     }
  1614.     bcopy((Address) modElemPtr->fdPtr, (Address) &(descPtr->common),
  1615.           sizeof(Fsdm_FileDescriptor));
  1616.     if (DiskWrite(diskId, descMapPtr->blockAddress,
  1617.             bufSize, descBuf) != bufSize) { 
  1618.         fprintf(stderr, "Write of decsriptor %s failed");
  1619.     }
  1620.     }
  1621. }
  1622.  
  1623.